Migo商城2.0 业务逻辑中添加redis 缓存(1) 十九

Migo商城2.0 业务逻辑中添加redis 缓存(1) 十九

分单机版和集群版,之前附件有说单机版了这里说下另外一种集群:

集群的搭建(伪分布式)

集群中至少有三个节点(选举模式),每个节点有一备份节点。需要6台服务器。

需要6个redis实例。需要每个实例运行在不同的端口号。

搭建步骤:

第一步:创建6个redis实例

第二步:修改redis的配置文件,修改端口号,开启集群。

第三步:启动每个redis实例。

第四步:创建集群,需要使用ruby脚本。需要安装ruby环境。

安装ruby

1
2
yum install ruby
yum install rubygems

安装rubyredis的接口程序:

拷贝redis-3.0.0.gem/usr/local

执行:

1
gem install /usr/local/redis-3.0.0.gem

使用redis-trib.rb脚本创建集群。

第五步:执行创建集群命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
[root@localhost redis-cluster]# ./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005  192.168.25.153:7006
>>> Creating cluster
Connecting to node 192.168.25.153:7001: OK
Connecting to node 192.168.25.153:7002: OK
Connecting to node 192.168.25.153:7003: OK
Connecting to node 192.168.25.153:7004: OK
Connecting to node 192.168.25.153:7005: OK
Connecting to node 192.168.25.153:7006: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.25.153:7001
192.168.25.153:7002
192.168.25.153:7003
Adding replica 192.168.25.153:7004 to 192.168.25.153:7001
Adding replica 192.168.25.153:7005 to 192.168.25.153:7002
Adding replica 192.168.25.153:7006 to 192.168.25.153:7003
M: be19d1b9fe8efa5c136defcce7562dcafce74ede 192.168.25.153:7001
slots:0-5460 (5461 slots) master
M: 5c4f1a5bab8717c3631809d781e08589924b1377 192.168.25.153:7002
slots:5461-10922 (5462 slots) master
M: 26a456a8757a2685ea0cad2bad4e946503c54871 192.168.25.153:7003
slots:10923-16383 (5461 slots) master
S: 40430837d5120024d40a4f96066ab6e2ddef73f2 192.168.25.153:7004
replicates be19d1b9fe8efa5c136defcce7562dcafce74ede
S: ae04c79dded411921b84dbef93afc485673d6408 192.168.25.153:7005
replicates 5c4f1a5bab8717c3631809d781e08589924b1377
S: 5d8886d27f2e45f2b617ae5474f187f53e36309e 192.168.25.153:7006
replicates 26a456a8757a2685ea0cad2bad4e946503c54871
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join....
>>> Performing Cluster Check (using node 192.168.25.153:7001)
M: be19d1b9fe8efa5c136defcce7562dcafce74ede 192.168.25.153:7001
slots:0-5460 (5461 slots) master
M: 5c4f1a5bab8717c3631809d781e08589924b1377 192.168.25.153:7002
slots:5461-10922 (5462 slots) master
M: 26a456a8757a2685ea0cad2bad4e946503c54871 192.168.25.153:7003
slots:10923-16383 (5461 slots) master
M: 40430837d5120024d40a4f96066ab6e2ddef73f2 192.168.25.153:7004
slots: (0 slots) master
replicates be19d1b9fe8efa5c136defcce7562dcafce74ede
M: ae04c79dded411921b84dbef93afc485673d6408 192.168.25.153:7005
slots: (0 slots) master
replicates 5c4f1a5bab8717c3631809d781e08589924b1377
M: 5d8886d27f2e45f2b617ae5474f187f53e36309e 192.168.25.153:7006
slots: (0 slots) master
replicates 26a456a8757a2685ea0cad2bad4e946503c54871
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost redis-cluster]#
./redis-trib.rb create --replicas 1 192.168.131.102:7001 192.168.131.102:7002 192.168.131.102:7003 192.168.131.102:7004 192.168.131.102:7005 192.168.131.102:7006
1
2
[root@localhost redis-cluster]# redis01/redis-cli -p 7004 -c
连接集群需要添加-c参数

项目中导入jedis的依赖,因为各个系统都有可能加缓存,所以,代码实现放在common工程中,注意事项看代码中的解释

这里就涉及到了什么时候定义接口和实现,同一个接口可以有不一样的实现,这里是分为单机版和集群版两种实现,这就是所谓的面向接口

先定义一个接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.migo.service;

/**
* Author 知秋
* Created by kauw on 2016/12/7.
*/
public interface JedisClient {
String get(String key);
String set(String key,String value);
String hget(String hkey,String key);
long hset(String hkey,String key,String value);
long incr(String key);
long decr(String key);
long expire(String key,int second);
long ttl(String key);
long del(String key);
long hdel(String hkey,String key);
}

单机版redis实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package com.migo.service.impl;

import com.migo.service.JedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
* Author 知秋
* Created by kauw on 2016/12/7.
*/
public class JedisClientSingle implements JedisClient {
/**
* 有些系统可能不需要添加redis缓存,反而依赖了common项目,但是自己容器内又没有对redis做相应配置,
* 故 required = false 这样就可以做到,容器内有则注入,没有就忽略
*/

@Autowired(required = false)
private JedisPool jedisPool;

@Override
public String get(String key) {
Jedis jedis=jedisPool.getResource();
String result=jedis.get(key);
jedis.close();
return result;
}

@Override
public String set(String key, String value) {
Jedis jedis=jedisPool.getResource();
String result=jedis.set(key, value);
jedis.close();
return result;
}

@Override
public String hget(String hkey, String key) {
Jedis jedis=jedisPool.getResource();
String result=jedis.hget(hkey, key);
jedis.close();
return result;
}

@Override
public long hset(String hkey, String key, String value) {
Jedis jedis=jedisPool.getResource();
Long result = jedis.hset(hkey, key, value);
jedis.close();
return result;
}

@Override
public long incr(String key) {
Jedis jedis=jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;
}

@Override
public long decr(String key) {
Jedis jedis=jedisPool.getResource();
Long result = jedis.decr(key);
jedis.close();
return result;
}

@Override
public long expire(String key, int second) {
Jedis jedis=jedisPool.getResource();
Long result = jedis.expire(key, second);
jedis.close();
return result;
}

@Override
public long ttl(String key) {
Jedis jedis=jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;
}

@Override
public long del(String key) {
Jedis jedis=jedisPool.getResource();
Long result = jedis.del(key);
jedis.close();
return result;
}

@Override
public long hdel(String hkey, String key) {
Jedis jedis=jedisPool.getResource();
Long result = jedis.hdel(hkey, key);
jedis.close();
return result;
}
}

集群版redis实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.migo.service.impl;

import com.migo.service.JedisClient;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.JedisCluster;

/**
* Author 知秋
* Created by kauw on 2016/12/7.
*/
public class JedisClientCluster implements JedisClient {
/**
* 有些系统可能不需要添加redis缓存,反而依赖了common项目,但是自己容器内又没有对redis做相应配置,
* 故 required = false 这样就可以做到,容器内有则注入,没有就忽略
*/
@Autowired(required = false)
private JedisCluster jedisCluster;


@Override
public String get(String key) {
return jedisCluster.get(key);
}

@Override
public String set(String key, String value) {

return jedisCluster.set(key, value);
}

@Override
public String hget(String hkey, String key) {
return jedisCluster.hget(hkey, key);
}

@Override
public long hset(String hkey, String key, String value) {
return jedisCluster.hset(hkey, key, value);
}

@Override
public long incr(String key) {
return jedisCluster.incr(key);
}

@Override
public long decr(String key) {
return jedisCluster.decr(key);
}

@Override
public long expire(String key, int second) {
return jedisCluster.expire(key, second);
}

@Override
public long ttl(String key) {
return jedisCluster.ttl(key);
}

@Override
public long del(String key) {
return jedisCluster.del(key);
}

@Override
public long hdel(String hkey, String key) {
return jedisCluster.hdel(hkey,key);
}
}

抽取模板方法

单机版那里可以看到方法里有比较多的重复代码,这里就讲一下Spring对模板代码的抽取方法:

拿大家最熟悉的jdbctemplate为例:

第一步 任务逻辑接口(自己需要实现的逻辑):

WorkCallback 参考上图中的1,因参数未知类型,所以设置为E

1
2
3
4
5
6
7
8
9
package com.migo.service;

/**
* Author 知秋
* Created by kauw on 2016/12/8.
*/
public interface WorkCallback<T,E> {
T doWorkCallback(E e);
}

第二步 实现类中定义execute方法

返回类型依然是T 参考上图中23,参数就是第一步代码中定义的接口实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private <T> T excute(WorkCallback<T,Jedis> workCallback){
Jedis jedis=null;
try {
jedis = jedisPool.getResource();
return workCallback.doWorkCallback(jedis);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (null !=jedis){
jedis.close();
}
}
return null;
}

第三步,调用类中调用excute方法并实现相应接口任务逻辑

因为要传入的是类型,所以返回的long修改为装箱类Long

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package com.migo.service.impl;

import com.migo.service.JedisClient;
import com.migo.service.WorkCallback;
import org.springframework.beans.factory.annotation.Autowired;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
* Author 知秋
* Created by kauw on 2016/12/7.
*/
public class JedisClientSingle implements JedisClient {
/**
* 有些系统可能不需要添加redis缓存,反而依赖了common项目,但是自己容器内又没有对redis做相应配置,
* 故 required = false 这样就可以做到,容器内有则注入,没有就忽略
*/

@Autowired(required = false)
private JedisPool jedisPool;

private <T> T excute(WorkCallback<T,Jedis> workCallback){
Jedis jedis=null;
try {
jedis = jedisPool.getResource();
return workCallback.doWorkCallback(jedis);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (null !=jedis){
jedis.close();
}
}
return null;
}

@Override
public String get(final String key) {
/*Jedis jedis=jedisPool.getResource();
String result=jedis.get(key);
jedis.close();
return result;*/
return this.excute(new WorkCallback<String, Jedis>() {
@Override
public String doWorkCallback(Jedis jedis) {
return jedis.get(key);
}
});
}

@Override
public String set(final String key, final String value) {

return this.excute(new WorkCallback<String, Jedis>() {
@Override
public String doWorkCallback(Jedis jedis) {
return jedis.set(key, value);
}
});
}

@Override
public String hget(final String hkey, final String key) {
/*Jedis jedis=jedisPool.getResource();
String result=jedis.hget(hkey, key);
jedis.close();
return result;*/
return this.excute(new WorkCallback<String, Jedis>() {
@Override
public String doWorkCallback(Jedis jedis) {
return jedis.hget(hkey, key);
}
});
}

@Override
public Long hset(final String hkey, final String key, final String value) {
/*Jedis jedis=jedisPool.getResource();
Long result = jedis.hset(hkey, key, value);
jedis.close();
return result;*/
return this.excute(new WorkCallback<Long, Jedis>() {
@Override
public Long doWorkCallback(Jedis jedis) {
return jedis.hset(hkey, key, value);
}
});
}

@Override
public Long incr(final String key) {
/*Jedis jedis=jedisPool.getResource();
Long result = jedis.incr(key);
jedis.close();
return result;*/
return this.excute(new WorkCallback<Long, Jedis>() {
@Override
public Long doWorkCallback(Jedis jedis) {
return jedis.incr(key);
}
});
}

@Override
public Long decr(final String key) {
/*Jedis jedis=jedisPool.getResource();
Long result = jedis.decr(key);
jedis.close();
return result;*/
return this.excute(new WorkCallback<Long, Jedis>() {
@Override
public Long doWorkCallback(Jedis jedis) {
return jedis.decr(key);
}
});
}

@Override
public Long expire(final String key, final int second) {
/*Jedis jedis=jedisPool.getResource();
Long result = jedis.expire(key, second);
jedis.close();
return result;*/
return this.excute(new WorkCallback<Long, Jedis>() {
@Override
public Long doWorkCallback(Jedis jedis) {
return jedis.expire(key, second);
}
});
}

@Override
public Long ttl(final String key) {
/*Jedis jedis=jedisPool.getResource();
Long result = jedis.ttl(key);
jedis.close();
return result;*/
return this.excute(new WorkCallback<Long, Jedis>() {
@Override
public Long doWorkCallback(Jedis jedis) {
return jedis.ttl(key);
}
});
}

@Override
public Long del(final String key) {
/*Jedis jedis=jedisPool.getResource();
Long result = jedis.del(key);
jedis.close();
return result;*/
return this.excute(new WorkCallback<Long, Jedis>() {
@Override
public Long doWorkCallback(Jedis jedis) {
return jedis.del(key);
}
});
}

@Override
public Long hdel(final String hkey, final String key) {
/*Jedis jedis=jedisPool.getResource();
Long result = jedis.hdel(hkey, key);
jedis.close();
return result;*/
return this.excute(new WorkCallback<Long, Jedis>() {
@Override
public Long doWorkCallback(Jedis jedis) {
return jedis.hdel(hkey,key);
}
});
}
}

改造完毕,其实模板类方法的设计也不过如此

Springjedis的整合

migo-manage web项目中的service配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
<!-- 配置包扫描器 -->
<context:component-scan base-package="com.migo.service"/>
<!-- 配置redis客户端单机版 -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="192.168.42.131"/>
<constructor-arg name="port" value="6379"/>
</bean>
<!-- 配置redis客户端实现类 -->
<bean id="jedisClientSingle" class="com.migo.service.impl.JedisClientSingle"/>
<!-- 配置redis客户端集群版 -->
<!--<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg>
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.42.131"/>
<constructor-arg name="port" value="7001"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.42.131"/>
<constructor-arg name="port" value="7002"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.42.131"/>
<constructor-arg name="port" value="7003"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.42.131"/>
<constructor-arg name="port" value="7004"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.42.131"/>
<constructor-arg name="port" value="7005"/>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg name="host" value="192.168.42.131"/>
<constructor-arg name="port" value="7006"/>
</bean>
</set>
</constructor-arg>
</bean>
<bean id="jedisClientCluster" class="com.migo.service.impl.JedisClientCluster"/>-->

</beans>
您的支持将鼓励我继续创作!